package com.helin.helinhealth.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * JWT工具类
 * 
 * <p>
 * 该工具类用于处理JWT令牌的生成、解析和验证。
 * JWT（JSON Web Token）是一种基于JSON的开放标准，用于在不同系统之间安全地传输声明。
 * 在本应用中，JWT主要用于用户身份认证和会话管理。
 * </p>
 * 
 * <p>
 * 主要功能包括：
 * - 生成JWT令牌
 * - 从令牌中提取声明（如用户ID）
 * - 验证令牌是否有效
 * - 检查令牌是否过期
 * </p>
 */
@Component
public class JwtUtils {

    /**
     * JWT签名密钥，从配置文件中注入
     */
    @Value("${jwt.secret-key}")
    private String secretKey;

    /**
     * 令牌有效期（毫秒），从配置文件中注入
     */
    @Value("${jwt.token-validity}")
    private long tokenValidity;

    /**
     * 从令牌中提取用户OpenID
     * 
     * @param token JWT令牌
     * @return 用户OpenID
     */
    public String extractOpenid(String token) {
        return extractClaim(token, claims -> claims.get("openid", String.class));
    }

    /**
     * 从令牌中提取过期时间
     * 
     * @param token JWT令牌
     * @return 过期时间
     */
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    /**
     * 从令牌中提取指定声明
     * 
     * @param token JWT令牌
     * @param claimsResolver 声明解析函数
     * @return 声明值
     */
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 解析令牌，提取所有声明
     * 
     * @param token JWT令牌
     * @return 所有声明
     */
    private Claims extractAllClaims(String token) {
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
        return Jwts.parser()
                .verifyWith(key)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    /**
     * 检查令牌是否已过期
     * 
     * @param token JWT令牌
     * @return 是否已过期
     */
    private Boolean isTokenExpired(String token) {
        try {
            final Date expiration = extractExpiration(token);
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 为指定用户生成JWT令牌
     * 
     * @param openid 用户OpenID
     * @return JWT令牌
     */
    public String generateToken(String openid) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("openid", openid);
        return createToken(claims);
    }

    /**
     * 创建JWT令牌
     * 
     * @param claims 声明键值对
     * @return JWT令牌
     */
    private String createToken(Map<String, Object> claims) {
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
        return Jwts.builder()
                .claims(claims)
                .issuedAt(new Date(System.currentTimeMillis()))
                .expiration(new Date(System.currentTimeMillis() + tokenValidity))
                .signWith(key)
                .compact();
    }

    /**
     * 验证令牌是否有效
     * 
     * @param token JWT令牌
     * @return 是否有效
     */
    public Boolean validateToken(String token) {
        try {
            return !isTokenExpired(token);
        } catch (Exception e) {
            return false;
        }
    }
} 